#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "A2C.h"
#include "example-everything.h"

/* We know the lack of indentation is not pretty. Lack of indenting
       works better for an example. */

int main(int argc, char * argv[])
{
/* Used everywhere */
A2C_ERROR           err;

/* For printing, encoding, and validating */
A2C_STREAM *        printStream_ptr = 0;
A2C_STREAM *        encodeStream_ptr = 0;
A2C_STREAM *        validateStream_ptr = 0;
A2C_CONTEXT *       context_ptr = NULL;
char *              char_buff_ptr = NULL;
unsigned char *     unchar_buff_ptr = NULL;
int                 buff_len;
char *              pathName = NULL;
char *              typeName = NULL;
char *              message = NULL;

/* The type pointers */
BM1 * BM1_ptr;
BO1 * BO1_ptr;
BS1 * BS1_ptr;
BS2 * BS2_ptr;
CH1 * CH1_ptr;
EN1 * EN1_ptr;
GE1 * GE1_ptr;
GR1 * GR1_ptr;
IA1 * IA1_ptr;
IN1 * IN1_ptr;
IN2 * IN2_ptr;
IN3 * IN3_ptr;
IS1 * IS1_ptr;
NS1 * NS1_ptr;
NU1 * NU1_ptr;
OB1 * OB1_ptr;
OC1 * OC1_ptr;
OD1 * OD1_ptr;
PR1 * PR1_ptr;
RO1 * RO1_ptr;
SE1 * SE1_ptr;
SE2 * SE2_ptr;
SF1 * SF1_ptr;
SQ1 * SQ1_ptr;
SQ2 * SQ2_ptr;
SQ3 * SQ3_ptr;
SR1 * SR1_ptr;
T61 * T61_ptr;
TE1 * TE1_ptr;
UC1 * UC1_ptr;
UN1 * UN1_ptr;
UT1 * UT1_ptr;
VD1 * VD1_ptr;
VI1 * VI1_ptr;
ValStruct * ValStruct_ptr;

/* Type-specific stuff */
int                 counter;
int                 hIntLen;
int                 numberToAllocate;
int                 numberUsed;
int                 objectBuffLen;
int                 someNum;
A2C_ERROR           bitstringError;
char                ASCIIIncludingControl[128];
char                ASCIIPrintable[96];
uint16              BMPHolderArray[] = {'a', 'b', 'c', 0};
uint16              BadBMPHolderArray[] = {0xFDD0, 0};
uint32              UnivHolderArray[] = {'d', 'e', 'f', 'g', 'h', 0};
char                UTF8Text[100];
A2C_NAMES const *   bitStringNamesStructPtr;
int                 bitStringVal;
const char *        bitStringName;
A2C_NAMES const *   enumNamesStructPtr;
int                 enumVal;
char const *        enumName;
A2C_NAMES const *   intNamesStructPtr;
int                 intVal;
const char *        intName;
char                ValText1[100];
char                ValText2[100];
char                ValText3[100];
char                ValText4[100];

/* Set up the memory stream, to be used by everyone */
err  = A2C_CreateMemoryStream(&printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); }

/* Set up the encode stream, to be used by everyone */
err = A2C_CreateMemoryStream(&encodeStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); }

/* Set up the validation text stream, to be used by everyone */
err = A2C_CreateMemoryStream(&validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); }

/* Make a table of all the ASCII characters, including the control characters
       Note, however, that this **does not** include NULL, which would mess
       up C incredibly. */
for(counter=0; counter<=126; counter++) {
    ASCIIIncludingControl[counter] = (char)(counter+1);
};
ASCIIIncludingControl[127] = '\0';

/* Make a table of all the printable ASCII characters, including space.  */
for(counter=0; counter<=94; counter++) {
    ASCIIPrintable[counter] = (char)(counter+32);
};
ASCIIPrintable[95] = '\0';

/* BM1 ::= BMPString */
/* Notes:
   Because BMPString used uint16 *, we can't fill it with normal C strings.
       This example fills it with three characters.
*/
printf("\n***BM1***\n");
err = A2C_Alloc_BM1(&BM1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* Remember that this is an array of uint16 */
/* This means that the order of the bytes in each element of the array
      is machine-dependent. The order output from the encoder will always
      be in network byte order. A2C_Print will output the hex of what is
      in memory, ignoring the fact that this is uint16.
      Note the differences in the output here. */
BM1_ptr->string = BMPHolderArray;
printf("The elements in BM1 (in hex) are: ");
for(counter=0; counter<(sizeof(BMPHolderArray)/sizeof(BMPHolderArray[0])); counter++)
    printf("%04x ", BM1_ptr->string[counter]);
printf("\n");
err = A2C_EncodeDer_BM1(BM1_ptr, 0, NULL, encodeStream_ptr);
if (err < A2C_ERROR_Success) { exit(err); }
err = A2C_GetDataFromStream(encodeStream_ptr, &unchar_buff_ptr, &buff_len);
if (err < A2C_ERROR_Success) { exit(err); }
printf("The encoding of BM1 (in hex) is: ");
for (counter=0; counter<buff_len; counter++) printf("%02x ", unchar_buff_ptr[counter]);
printf("\n");
err = A2C_Print_BM1(BM1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of BM1_ptr is %s\n", char_buff_ptr);
/* Examples of A2C_Valdiate and A2C_Validate2 */
printf("Checking validity of original string\n");
err = A2C_Validate_BM1(BM1_ptr, &someNum);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate\n", char_buff_ptr);
};
err = A2C_Validate2_BM1(BM1_ptr, NULL, &someNum, validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate2\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate2\n", char_buff_ptr);
    err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
    printf("The information from A2C_Validate2 is\n%s", char_buff_ptr);
};
/* An example of a bad character (U+FDD0) */
printf("Checking validity of bad character (FDD0)\n");
BM1_ptr->string = BadBMPHolderArray;
printf("The elements in BM1 (in hex) are: ");
for(counter=0; counter<(sizeof(BadBMPHolderArray)/sizeof(BadBMPHolderArray[0])); counter++)
    printf("%04x ", BM1_ptr->string[counter]);
printf("\n");
err = A2C_Print_BM1(BM1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of BM1_ptr is %s\n", char_buff_ptr);
err = A2C_Validate_BM1(BM1_ptr, &someNum);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate\n", char_buff_ptr);
};
err = A2C_Validate2_BM1(BM1_ptr, NULL, &someNum, validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate2\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate2\n", char_buff_ptr);
    err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
    printf("The information from A2C_Validate2 is\n%s", char_buff_ptr);
};

/* BO1 ::= BOOLEAN */
printf("\n***BO1***\n");
err = A2C_Alloc_BO1(&BO1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
BO1_ptr->data = 1;
err = A2C_Print_BO1(BO1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of BO1_ptr is %s\n", char_buff_ptr);

/* BS1 ::= BIT STRING */
/* Notes:
    The data must be allocated before it is used. In this case,
        "calloc" is used so that the field starts off zero-filled.
*/
printf("\n***BS1***\n");
err = A2C_Alloc_BS1(&BS1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
objectBuffLen = 2;
BS1_ptr->data = calloc(objectBuffLen, 1);
BS1_ptr->bufferLength = objectBuffLen;
BS1_ptr->bitLength = 13;
printf("The buffer length is %i and the number of bits used is %i\n",
    BS1_ptr->bufferLength, BS1_ptr->bitLength);
/* Set bit 10 */
A2C_BIT_STRING_Set(BS1_ptr, 10);
printf("Bit 10 should be 1: ");
bitstringError = A2C_BIT_STRING_IsSet(BS1_ptr, 10);
if(bitstringError == A2C_ERROR_False) { printf("Bit 10 is 0\n"); }
else if(bitstringError == A2C_ERROR_True) { printf("Bit 10 is 1\n"); }
else { printf("Error when testing bit 10: %i\n", bitstringError); exit(1); };
/* Clear bit 10 */
A2C_BIT_STRING_Clear(BS1_ptr, 10);
printf("Bit 10 should now be 0: ");
bitstringError = A2C_BIT_STRING_IsSet(BS1_ptr, 10);
if(bitstringError == A2C_ERROR_False) { printf("Bit 10 is 0\n"); }
else if(bitstringError == A2C_ERROR_True) { printf("Bit 10 is 1\n"); }
else { printf("Error when testing bit 10\n"); exit(1); };
printf("Bit 9 should be 0: ");
bitstringError = A2C_BIT_STRING_IsSet(BS1_ptr, 9);
if(bitstringError == A2C_ERROR_False) { printf("Bit 9 is 0\n"); }
else if(bitstringError == A2C_ERROR_True) { printf("Bit 9 is 1\n"); }
else { printf("Error when testing bit 9\n"); exit(1); };
err = A2C_Print_BS1(BS1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of BS1_ptr is %s\n", char_buff_ptr);

/* BS2 ::= BIT STRING { bs2val1 (3), bs2val2 (5) } */
/* Notes:
    This shows how to use BIT STRINGS with defined values.
*/
printf("\n***BS2***\n");
err = A2C_Alloc_BS2(&BS2_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
objectBuffLen = 2;
BS2_ptr->data = calloc(objectBuffLen, 1);
BS2_ptr->bufferLength = objectBuffLen;
BS2_ptr->bitLength = 10;
printf("The buffer length is %i and the number of bits used is %i\n",
    BS2_ptr->bufferLength, BS2_ptr->bitLength);
A2C_List_BS2(&bitStringNamesStructPtr);
if (err < A2C_ERROR_Success) { exit(1); };
printf("BS2 has %i values\n", bitStringNamesStructPtr->count);
for (counter=0; counter<bitStringNamesStructPtr->count; counter++) {
    printf("For element %i, the name is %s and the value is %i\n",
        counter+1, bitStringNamesStructPtr->listArrayPtr[counter].name,
        bitStringNamesStructPtr->listArrayPtr[counter].number);
}
/* Find the value of the element named "bs2val2" */
A2C_NameToInt_BS2("bs2val2", &bitStringVal);
printf("The value of bs2val2 is %i\n", bitStringVal);
/* Find the name of the element 3 */
A2C_IntToName_BS2(3, &bitStringName);
printf("The name of 3 is %s\n", bitStringName);

/* Set the bits in the one named "bs2val1" and "bs2val2" */
A2C_NameToInt_BS2("bs2val1", &bitStringVal);
A2C_BIT_STRING_Set(BS2_ptr, bitStringVal);
A2C_NameToInt_BS2("bs2val2", &bitStringVal);
A2C_BIT_STRING_Set(BS2_ptr, bitStringVal);

err = A2C_Print_BS2(BS2_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of BS2_ptr is %s\n", char_buff_ptr);

/* CH1 ::= CHOICE { ch1Int [5] INTEGER, ch1IA5 [6] IA5String } */
/* Notes:
   CHOICE creates a union, so we need to set the value after we set
       the index. If we set the values all at once, the last one would win.
   The index is set based on the defines in .h file. In this case, those are:
        #define CH1_ch1Int_index 0
        #define CH1_ch1IA5_index 1
*/
printf("\n***CH1***\n");
err = A2C_Alloc_CH1(&CH1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
CH1_ptr->index = CH1__u_ch1Int_index;
CH1_ptr->u.ch1Int.nData = 2345;
printf("The choice is now the integer: ");
err = A2C_Print_CH1(CH1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of CH1_ptr is %s\n", char_buff_ptr);
CH1_ptr->index = CH1__u_ch1IA5_index;
CH1_ptr->u.ch1IA5.string = "two three four five";
printf("The choice is now the IA5String: ");
err = A2C_Print_CH1(CH1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of CH1_ptr is %s\n", char_buff_ptr);

/* EN1 ::= ENUMERATED { en1val1 (7), en1val2 (8) } */
/* Notes:
    This is done as a native integer
*/
printf("\n***EN1***\n");
err = A2C_Alloc_EN1(&EN1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_List_EN1(&enumNamesStructPtr);
if (err < A2C_ERROR_Success) { exit(1); };
printf("EN1 has %i values\n", enumNamesStructPtr->count);
for (counter=0; counter<enumNamesStructPtr->count; counter++) {
    printf("For element %i, the name is %s and the value is %i\n",
        counter+1, enumNamesStructPtr->listArrayPtr[counter].name,
        enumNamesStructPtr->listArrayPtr[counter].number);
}
/* Find the value of the element named "en1val2" */
A2C_NameToInt_EN1("en1val2", &enumVal);
printf("The value of en1val2 is %i\n", enumVal);
/* Find the name of the element 7 */
A2C_IntToName_EN1(7, &enumName);
printf("The name of 7 is %s\n", enumName);
/* Set this item to the one named "en1val2" */
A2C_NameToInt_EN1("en1val2", &(EN1_ptr->nData));
err = A2C_Print_EN1(EN1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of EN1_ptr is %s\n", char_buff_ptr);

/* GE1 ::= GeneralizedTime */
printf("\n***GE1***\n");
err = A2C_Alloc_GE1(&GE1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
GE1_ptr->string = "20070908163000Z";
err = A2C_Print_GE1(GE1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of GE1_ptr is %s\n", char_buff_ptr);

/* GR1 ::= GraphicString */
printf("\n***GR1***\n");
err = A2C_Alloc_GR1(&GR1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
GR1_ptr->string = "Poorly defined repertoire and encoding";
err = A2C_Print_GR1(GR1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of GR1_ptr is %s\n", char_buff_ptr);

/* IA1 ::= IA5String */
printf("\n***IA1***\n");
err = A2C_Alloc_IA1(&IA1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
IA1_ptr->string = ASCIIIncludingControl;
err = A2C_Print_IA1(IA1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of IA1_ptr is %s\n", char_buff_ptr);

/* IN1 ::= INTEGER */
/* Notes:
    This is done as a native integer.
*/
printf("\n***IN1***\n");
err = A2C_Alloc_IN1(&IN1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
IN1_ptr->nData = -33445;
err = A2C_Print_IN1(IN1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of IN1_ptr is %s\n", char_buff_ptr);

/* IN2 ::= INTEGER */
/* Notes:
    This is done as a huge integer; for this example, the length is 7.
*/
printf("\n***IN2***\n");
err = A2C_Alloc_IN2(&IN2_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
hIntLen = 7;
IN2_ptr->hData = calloc(hIntLen, 1);
IN2_ptr->hLength = hIntLen;
someNum = -33445;
/* Make sure the array is large enough */
if(sizeof(someNum) > hIntLen) { exit(1); }
for (counter=(hIntLen-1); counter>=0; counter--) {
    IN2_ptr->hData[counter] = (BYTE)(someNum & 0xff);
    someNum >>= 8;
}
err = A2C_Print_IN2(IN2_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of IN2_ptr is %s\n", char_buff_ptr);

/* IN3 ::= INTEGER { in3val1 (-3), in3val2 (14) } */
/* Notes:
    This shows how to use INTEGERs with defined values.
*/
printf("\n***IN3***\n");
err = A2C_Alloc_IN3(&IN3_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
objectBuffLen = 2;
A2C_List_IN3(&intNamesStructPtr);
if (err < A2C_ERROR_Success) { exit(1); };
printf("IN3 has %i values\n", intNamesStructPtr->count);
for (counter=0; counter<intNamesStructPtr->count; counter++) {
    printf("For element %i, the name is %s and the value is %i\n",
        counter+1, intNamesStructPtr->listArrayPtr[counter].name,
        intNamesStructPtr->listArrayPtr[counter].number);
}
/* Find the value of the element named "in3val2" */
A2C_NameToInt_IN3("in3val2", &intVal);
printf("The value of in3val2 is %i\n", intVal);
/* Find the name of the element -3 */
A2C_IntToName_IN3(-3, &intName);
printf("The name of -3 is %s\n", intName);
/* Set this item to the one named "in3val2" */
A2C_NameToInt_IN3("in3val2", &(IN3_ptr->nData));
err = A2C_Print_IN3(IN3_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of IN3_ptr is %s\n", char_buff_ptr);

/* IS1 ::= ISO646String */
printf("\n***IS1***\n");
err = A2C_Alloc_IS1(&IS1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
IS1_ptr->string = ASCIIPrintable;
err = A2C_Print_IS1(IS1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of IS1_ptr is %s\n", char_buff_ptr);

/* NS1 ::= NumericString */
printf("\n***NS1***\n");
err = A2C_Alloc_NS1(&NS1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* Space are allowed in NumericString */
NS1_ptr->string = "436 822";
err = A2C_Print_NS1(NS1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of NS1_ptr is %s\n", char_buff_ptr);

/* NU1 ::= NULL */
printf("\n***NU1***\n");
err = A2C_Alloc_NU1(&NU1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* The following is ignored */
NU1_ptr->dummy = 5;
err = A2C_Print_NU1(NU1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of NU1_ptr is %s\n", char_buff_ptr);

/* OB1 ::= OBJECT IDENTIFIER */
printf("\n***OB1***\n");
err = A2C_Alloc_OB1(&OB1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
OB1_ptr->oid = "1.5.33457.6";
err = A2C_Print_OB1(OB1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of OB1_ptr is %s\n", char_buff_ptr);

/* OC1 ::= OCTET STRING */
/* Notes:
    The data must be allocated before it is used. In this case,
        "calloc" is used so that the field starts off zero-filled.
*/
printf("\n***OC1***\n");
err = A2C_Alloc_OC1(&OC1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
objectBuffLen = 4;
OC1_ptr->data = calloc(objectBuffLen, 1);
OC1_ptr->length = objectBuffLen;
OC1_ptr->data[0] = 0xfa;
OC1_ptr->data[1] = 0xce;
err = A2C_Print_OC1(OC1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of OC1_ptr is %s\n", char_buff_ptr);

/* OD1 ::= ObjectDescriptor */
printf("\n***OD1***\n");
err = A2C_Alloc_OD1(&OD1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
OD1_ptr->string = "This describes the object, somewhat";
err = A2C_Print_OD1(OD1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of OD1_ptr is %s\n", char_buff_ptr);

/* PR1 ::= PrintableString */
printf("\n***PR1***\n");
err = A2C_Alloc_PR1(&PR1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
PR1_ptr->string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
err = A2C_Print_PR1(PR1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of PR1_ptr is %s\n", char_buff_ptr);

/* RO1 ::= RELATIVE-OID */
printf("\n***RO1***\n");
err = A2C_Alloc_RO1(&RO1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
RO1_ptr->oid = "45.12";
err = A2C_Print_RO1(RO1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of RO1_ptr is %s\n", char_buff_ptr);

/* SE1 ::= SET { se1Int INTEGER, se1PrintStr PrintableString } */
printf("\n***SE1***\n");
err = A2C_Alloc_SE1(&SE1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
SE1_ptr->se1Int.nData = 7788;
SE1_ptr->se1PrintStr.string = "seven seven eight eight";
err = A2C_Print_SE1(SE1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SE1_ptr is %s\n", char_buff_ptr);

/* SE2 ::= SET { lots of stuff } */
printf("\n***SE2***\n");
err = A2C_Alloc_SE2(&SE2_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
SE2_ptr->se2IN1.nData = 98;
SE2_ptr->se2PR1.string = "Inside the set";
err = A2C_Print_SE2(SE2_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SE2_ptr is %s\n", char_buff_ptr);

/* SF1 ::= SET OF INTEGER */
printf("\n***SF1***\n");
err = A2C_Alloc_SF1(&SF1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* Allocate 100, but only use 2 */
numberToAllocate = 100;
numberUsed = 2;
err = A2C_AllocArray_SF1(SF1_ptr, numberToAllocate);
if (err < A2C_ERROR_Success) { exit(1); }
printf("The number allocated is %i\n", SF1_ptr->countAllocated);
SF1_ptr->count = numberUsed;
SF1_ptr->array[0].nData = 12;
SF1_ptr->array[1].nData = -7;
err = A2C_Print_SF1(SF1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SF1_ptr is %s\n", char_buff_ptr);

/* SQ1 ::= SEQUENCE { seq1 INTEGER, seq2 TeletexString } */
printf("\n***SQ1***\n");
err = A2C_Alloc_SQ1(&SQ1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
SQ1_ptr->sq1Int.nData = -55689;
SQ1_ptr->sq1Tele.string = "abcde";
err = A2C_Print_SQ1(SQ1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SQ1_ptr is %s\n", char_buff_ptr);

/* SQ2 ::= SEQUENCE { lot of stuff } */
printf("\n***SQ2***\n");
err = A2C_Alloc_SQ2(&SQ2_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
SQ2_ptr->sq2IN1.nData = 335;
SQ2_ptr->sq2PR1.string = "Inside the sequence";
err = A2C_Print_SQ2(SQ2_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SQ2_ptr is %s\n", char_buff_ptr);

/* SQ3 ::= SEQUENCE { sq3Int1 INTEGER, sq3Int2 INTEGER OPTIONAL,
        sq3Str IA5String } */
/* Notes:
     The .h file contains:
         #define SQ3_sq3Int2_present 1
     This defines a bit position that is a power of 2 for the name.
     Use that bit position with optionalFields to say what is and is not
         used in the sequence.
*/
printf("\n***SQ3***\n");
err = A2C_Alloc_SQ3(&SQ3_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
SQ3_ptr->sq3Int1.nData = 17;
SQ3_ptr->sq3Int2.nData = 34;
SQ3_ptr->sq3Str.string = "fleerling";
/* Make sq3Int2 present by turning its bit on */
SQ3_ptr->optionalFields |= SQ3_sq3Int2_present;
printf("With the optional integer included:\n");
err = A2C_Print_SQ3(SQ3_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SQ3_ptr is %s\n", char_buff_ptr);
/* Make sq3Int2 absent by turning its bit off */
SQ3_ptr->optionalFields &= ~SQ3_sq3Int2_present;
printf("With the optional integer not included:\n");
err = A2C_Print_SQ3(SQ3_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SQ3_ptr is %s\n", char_buff_ptr);

/* SR1 ::= SEQUENCE OF INTEGER */
printf("\n***SR1***\n");
err = A2C_Alloc_SR1(&SR1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* Allocate 50, but only use 3 */
numberToAllocate = 50;
numberUsed = 3;
err = A2C_AllocArray_SR1(SR1_ptr, numberToAllocate);
if (err < A2C_ERROR_Success) { exit(1); }
printf("The number allocated is %i\n", SR1_ptr->countAllocated);
SR1_ptr->count = numberUsed;
SR1_ptr->array[0].nData = -17;
SR1_ptr->array[1].nData = 6616;
SR1_ptr->array[2].nData = 1000000;
err = A2C_Print_SR1(SR1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of SR1_ptr is %s\n", char_buff_ptr);

/* T61 ::= T61String    */
printf("\n***T61***\n");
err = A2C_Alloc_T61(&T61_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
T61_ptr->string = "Poorly defined repertoire and encoding";
err = A2C_Print_T61(T61_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of T61_ptr is %s\n", char_buff_ptr);

/* TE1 ::= TeletexString */
printf("\n***TE1***\n");
err = A2C_Alloc_TE1(&TE1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
TE1_ptr->string = "Poorly defined repertoire and encoding";
err = A2C_Print_TE1(TE1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of TE1_ptr is %s\n", char_buff_ptr);

/* UC1 ::= UTCTime */
printf("\n***UC1***\n");
err = A2C_Alloc_UC1(&UC1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
UC1_ptr->string = "100908070605Z";
err = A2C_Print_UC1(UC1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of UC1_ptr is %s\n", char_buff_ptr);

/* UN1 ::= UniversalString */
printf("\n***UN1***\n");
err = A2C_Alloc_UN1(&UN1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* Remember that this is an array of uint32 */
/* This means that the order of the bytes in each element of the array
      is machine-dependent. The order output from the encoder will always
      be in network byte order. A2C_Print will output the hex of what is
      in memory, ignoring the fact that this is uint32.
      Note the differences in the output here. */
UN1_ptr->string = UnivHolderArray;
printf("The elements in BM1 (in hex) are: ");
for(counter=0; counter<(sizeof(UnivHolderArray)/sizeof(UnivHolderArray[0])); counter++)
    printf("%08x ", UN1_ptr->string[counter]);
printf("\n");
err = A2C_EncodeDer_UN1(UN1_ptr, 0, NULL, encodeStream_ptr);
if (err < A2C_ERROR_Success) { exit(err); }
err = A2C_GetDataFromStream(encodeStream_ptr, &unchar_buff_ptr, &buff_len);
if (err < A2C_ERROR_Success) { exit(err); }
printf("The encoding of UN1 (in hex) is: ");
for (counter=0; counter<buff_len; counter++) printf("%02x ", unchar_buff_ptr[counter]);
printf("\n");
err = A2C_Print_UN1(UN1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of UN1_ptr is %s\n", char_buff_ptr);

/* UT1 ::= UTF8String  */
printf("\n***UT1***\n");
err = A2C_Alloc_UT1(&UT1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
/* a with umlaut is U+00E4; UTF8 is C3A4 */
strcpy(UTF8Text, "The a with umlaut is: \xC3\xA4");
UT1_ptr->string = UTF8Text;
err = A2C_Print_UT1(UT1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of UT1_ptr is %s\n", char_buff_ptr);
/* Examples of A2C_Valdiate and A2C_Validate2 */
printf("Checking validity of original string\n");
err = A2C_Validate_UT1(UT1_ptr, &someNum);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate\n", char_buff_ptr);
};
err = A2C_Validate2_UT1(UT1_ptr, NULL, &someNum, validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate2\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate2\n", char_buff_ptr);
    err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
    printf("The information from A2C_Validate2 is\n%s", char_buff_ptr);
};
printf("Checking validity of bad string (not shortest form)\n");
/* An example of a bad encoding of ']' (not shortest form) */
strcpy(UTF8Text, "This encoding should fail: \xC1\x9D");
UT1_ptr->string = UTF8Text;
err = A2C_Print_UT1(UT1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of UT1_ptr is %s\n", char_buff_ptr);
err = A2C_Validate_UT1(UT1_ptr, &someNum);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate\n", char_buff_ptr);
};
err = A2C_Validate2_UT1(UT1_ptr, NULL, &someNum, validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate2\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate2\n", char_buff_ptr);
    err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
    printf("The information from A2C_Validate2 is\n%s", char_buff_ptr);
};
/* An example of a bad character (U+FDD0) */
printf("Checking validity of bad character (FDD0)\n");
strcpy(UTF8Text, "This character should fail: \xEF\xB7\x90");
UT1_ptr->string = UTF8Text;
err = A2C_Print_UT1(UT1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of UT1_ptr is %s\n", char_buff_ptr);
err = A2C_Validate_UT1(UT1_ptr, &someNum);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate\n", char_buff_ptr);
};
err = A2C_Validate2_UT1(UT1_ptr, NULL, &someNum, validateStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
if (someNum == 1) { printf("%s is valid in A2C_Validate2\n", char_buff_ptr); }
else {
    printf("%s is not valid in A2C_Validate2\n", char_buff_ptr);
    err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
    printf("The information from A2C_Validate2 is\n%s", char_buff_ptr);
};

/* VD1 ::= VideotexString */
printf("\n***VD1***\n");
err = A2C_Alloc_VD1(&VD1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
VD1_ptr->string = ASCIIPrintable;
err = A2C_Print_VD1(VD1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of VD1_ptr is %s\n", char_buff_ptr);

/* VI1 ::= VisibleString */
printf("\n***VI1***\n");
err = A2C_Alloc_VI1(&VI1_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
VI1_ptr->string = ASCIIPrintable;
err = A2C_Print_VI1(VI1_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of VI1_ptr is %s\n", char_buff_ptr);

printf("\n***DER encode SQ2 (the really big SEQUENCE) ***\n");
err = A2C_EncodeDer_SQ2(SQ2_ptr, 0, NULL, encodeStream_ptr);
if (err < A2C_ERROR_Success) { exit(err); }
err = A2C_GetDataFromStream(encodeStream_ptr, &unchar_buff_ptr, &buff_len);
if (err < A2C_ERROR_Success) { exit(err); }
printf("The encoding of SQ2 (in hex) is: ");
for (counter=0; counter<buff_len; counter++) printf("%02x ", unchar_buff_ptr[counter]);
printf("\n");

/* ValStruct ::= SEQUENCE { vs1 UT1, vs2 UT1, vs3 UT1, vs4 UT1} */
/* Example of using A2C_Validate2 when a structure has mulitple
      invalid fields */
printf("\n***Validating a structure***\n");
err = A2C_Alloc_ValStruct(&ValStruct_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
strcpy(ValText1, "Valid");
ValStruct_ptr->vs1.string = ValText1;
strcpy(ValText2, "Not valid: \xC1\x9D");
ValStruct_ptr->vs2.string = ValText2;
strcpy(ValText3, "Also valid");
ValStruct_ptr->vs3.string = ValText3;
strcpy(ValText4, "Not valid: \xEF\xB7\x90");
ValStruct_ptr->vs4.string = ValText4;

err = A2C_Print_ValStruct(ValStruct_ptr, printStream_ptr);
if (err < A2C_ERROR_Success) { exit(1); };
err = A2C_GetStringFromStream(printStream_ptr, &char_buff_ptr);
printf("The value of ValStruct_ptr is %s\n", char_buff_ptr);

context_ptr = NULL;
do {
    err = A2C_Validate2_ValStruct(ValStruct_ptr, &context_ptr, &someNum, validateStream_ptr);
    if (err != A2C_ERROR_Success) { /* There is an internal error; clean up */
        A2C_FreeContext(context_ptr);
        break;
   }
   if (someNum == 0) { /* Validation failed for this field */
        printf("Validation error\n");
        err = A2C_GetStringFromStream(validateStream_ptr, &char_buff_ptr);
        pathName = strtok(char_buff_ptr, "\n");
        typeName = strtok(NULL, "\n");
        message = strtok(NULL, "\n");
        printf("   The path is %s\n   The type name is %s\n   The message is %s\n",
            pathName, typeName, message);        
   }
} while (someNum == 0);


/* This is a bit sloppy: we should free up all the stuff we
      allocated. */
exit(0);
}

